<?php

namespace pmvc\log;

use DateTime;
use Exception;
use ReflectionObject;

class Logger {

	const TRACE		= 0;
	const FINE		= 10;
	const DEBUG		= 20;
	const INFO		= 30;
	const WARN		= 40;
	const ERROR		= 50;
	const FATAL		= 60;
	
	private $name;
	private $level;
	private $appender;

	public function __construct($name, $level, Appender $appender) {
		$this->name 	= $name;
		$this->level	= $level;
		$this->appender	= $appender;
	}
	
	public static function getLogger($name) {
		return LoggerManager::getInstance()->getLogger($name);
	}

	public function setAppender(Appender $appender) {
		$this->appender = $appender;
	}

	public function setLevel($level) {
		$this->level = $level;
	}

	public function getName() {
		return $this->name;
	}

	public function getLevel() {
		return $this->level;
	}

	public function getAppender() {
		return $this->appender;
	}
	
	public function trace() {
		$args = func_get_args();
		$message = array_shift($args);
		$this->log(self::TRACE, $message, $args);
	}
	
	public function fine() {
		$args = func_get_args();
		$message = array_shift($args);
		$this->log(self::FINE, $message, $args);
	}
	
	public function debug() {
		$args = func_get_args();
		$message = array_shift($args);
		$this->log(self::DEBUG, $message, $args);
	}
	
	public function info() {
		$args = func_get_args();
		$message = array_shift($args);
		$this->log(self::INFO, $message, $args);
	}
	
	public function warn() {
		$args = func_get_args();
		$message = array_shift($args);
		$this->log(self::WARN, $message, $args);
	}
	
	public function error() {
		$args = func_get_args();
		$message = array_shift($args);
		$this->log(self::ERROR, $message, $args);
	}
	
	public function fatal() {
		$args = func_get_args();
		$message = array_shift($args);
		$this->log(self::FATAL, $message, $args);
	}

	public function canLog($level) {
		return ($level >= $this->level);
	}

	public function log($level, $message, Array $args) {

		// make sure we should be logging this
		if (!$this->canLog($level)) { return; }

		// format the message
		$message = preg_replace_callback('/\{([0-9A-Za-z\._\-]+)\}/', function($matches)use($args) {
			$val = isset($args[$matches[1]]) ? $args[$matches[1]] : $matches[0];
			if ($val instanceof Exception) {
				$val = get_class($e).":".$e->getMessage();
			} else if (is_object($val)) {
				$clazz = new ReflectionObject($val);
				if ($clazz->hasMethod("__toString")) {
					$val = $val->__toString();
				} else {
					$val = get_class($val);
				}
			}
			return $val;
		}, $message);

		// add the exceptions to the log
		foreach ($args as $arg) {
			if ($arg instanceof Exception) {
				$message .= "\n". $this->formatExceptionMessage($arg);
			}
		}

		// append it
		$this->appender->append($level, new DateTime(), $this->name, $message);
	}

	private function formatExceptionMessage(Exception $e) {
		return get_class($e).":".$e->getMessage()."\n".preg_replace("/\n#|^#/", "\n\t#", $e->getTraceAsString());
	}

}

?>